import axios, { type AxiosRequestConfig, type AxiosInstance } from 'axios'
import { ResultEnum as REQUEST } from '@/enums/ResultEnum'
import Storage from './storage'
import { ElMessage, ElMessageBox } from 'element-plus'
import router from '@/router'
import { useUserStoreWidthOut } from '@/store/user'

// 是否显示重新登录
export let isReLogin = { show: false }

// 相关配置请参考：www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
	baseURL: import.meta.env.VITE_API_URL,
	// 请求超时时间
	timeout: REQUEST.TIMEOUT,
	// 设置跨域是否携带凭证
	withCredentials: true,
	headers: {
		'Content-Type': 'application/json;charset=utf-8'
	}
}

class Request {
	constructor() {
		this.httpInterceptorsRequest()
		this.httpInterceptorsResponse()
	}

	/** 保存当前`Axios`实例对象 */
	private static axiosInstance: AxiosInstance = axios.create(defaultConfig)

	/** 请求拦截 */
	private httpInterceptorsRequest(): void {
		Request.axiosInstance.interceptors.request.use(config => {
			if (Storage.get('token')) {
				config.headers[REQUEST.REQUEST_HEADER_TOKEN_FIELD] = Storage.get('token')
			}

			// 兼容get参数数组
			if (config.method === 'get' && config.params) {
				const filteredParams = Object.fromEntries(
					Object.entries(config.params).filter(([_, value]) => value !== null && value !== undefined && value !== '')
				) as { [key: string]: string }
				const params = new URLSearchParams(filteredParams).toString()

				config.url = config.url + '?' + params
				config.params = undefined
			}
			return config
		})
	}

	/** 响应拦截 */
	private httpInterceptorsResponse(): void {
		Request.axiosInstance.interceptors.response.use(
			response => {
				const code = response.data[REQUEST.RESPONSE_CODE_FIELD]
				const data = REQUEST.RESPONSE_DATA_FIELD ? response.data[REQUEST.RESPONSE_DATA_FIELD] : response.data
				const msg = response.data[REQUEST.RESPONSE_MSG_FIELD] || '系统错误，请稍候再试'
				// const requestParams = response.config.data || response.config.params || response.config.url?.split('?')?.[1]
				if (response.data instanceof Blob) {
					/**
					 * @description 导出接口 文件名称请求头中获取
					 * 系统工具-代码生成接口 /tool/gen/batchGenCode
					 * content-disposition attachment; filename="ruoyi.zip"
					 */
					const disposition = response.headers['content-disposition']
					let filename = ''
					if (disposition) {
						const match = disposition.match(/filename="?([^"]+)"?/)
						if (match) filename = decodeURIComponent(match[1])
					}
					const blobData = {
						filename: filename,
						data: response.data
					}
					// console.log('request: success->', url, requestParams, blobData)
					return blobData
				}
				// console.log('request: success->', url, requestParams, data)

				if (REQUEST.SUCCESS_CODE_ARR.includes(code)) return data
				if (REQUEST.RESPONSE_CODE_ERROR_AUTH === code) {
					this.errorAuthToast(msg)
				} else {
					this.errorToast(msg)
				}
				return Promise.reject(response)
			},
			error => {
				console.log('request: error->', error)
				const { code, message } = error || {}
				const err: string = error.toString()
				let msg = '系统错误，请稍候再试'
				if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
					msg = '接口请求超时，请刷新页面重试!'
				} else if (err && err.includes('Network Error')) {
					msg = '网络异常, 请检查您的网络连接是否正常'
				}
				this.errorToast(msg)
				return Promise.reject(error)
			}
		)
	}

	private errorToast(msg: string) {
		console.log('errorToast', msg)
		ElMessage({
			message: msg,
			type: 'error'
		})
	}
	/** 登录过期, 重新登录 */
	private errorAuthToast(msg: string) {
		if (isReLogin.show) return
		isReLogin.show = true
		console.log('errorAuthToast', msg)
		ElMessageBox.confirm('登录过期, 是否重新登录?', {
			title: '系统提示',
			type: 'warning',
			confirmButtonText: '确定',
			cancelButtonText: '取消',
			closeOnClickModal: false
		})
			.then(() => {
				isReLogin.show = false
				const userStore = useUserStoreWidthOut()
				userStore.resetUserInfo()
				router.replace('/login')
			})
			.catch(() => {
				isReLogin.show = false
			})
	}

	public request<T>(config: AxiosRequestConfig): Promise<T> {
		// 单独处理自定义请求/响应回调
		return new Promise((resolve, reject) => {
			Request.axiosInstance
				.request(config)
				.then((response: any) => {
					resolve(response)
				})
				.catch(error => {
					reject(error)
				})
		})
	}

	/** 单独抽离的`post`工具函数 */
	public post<T>(url: string, data?: AxiosRequestConfig['data'], config?: AxiosRequestConfig) {
		return this.request<ResponseData<T>>({
			method: 'post',
			url,
			data,
			...config
		})
	}

	/** 单独抽离的`post`工具函数 */
	public postFile<T>(url: string, data?: AxiosRequestConfig['data'], config?: AxiosRequestConfig) {
		return this.request<T>({
			method: 'post',
			url,
			data,
			...config
		})
	}

	/** 单独抽离的`get`工具函数 */
	public get<T>(url: string, params?: AxiosRequestConfig['params'], config?: AxiosRequestConfig) {
		return this.request<ResponseData<T>>({
			method: 'get',
			url,
			params,
			...config
		})
	}
	public put<T>(url: string, data?: AxiosRequestConfig['data'], config?: AxiosRequestConfig) {
		return this.request<ResponseData<T>>({
			method: 'put',
			url,
			data,
			...config
		})
	}

	public delete<T>(url: string, params?: AxiosRequestConfig['params'], config?: AxiosRequestConfig) {
		return this.request<ResponseData<T>>({
			method: 'delete',
			url,
			params,
			...config
		})
	}
}
export const http = new Request()
